﻿#region COPYRIGHT© 2009-2013 Phillip Clark. All rights reserved.

// For licensing information see License.txt (MIT style licensing).

#endregion

using System.Collections.Generic;
using System.Text;
using FlitBit.Core;

namespace FlitBit.Json
{
	public enum JsonOutputFormat
	{
		Readable = 0,
		Compact = 1,
		Pretty = 2,
	}

	public class JsonFormatter
	{
		readonly StringBuilder _buffer = new StringBuilder(400);
		string _firstMemberSeparator;
		int _indent = 0;
		string _memberSeparator;

		public string FirstMemberSeparator { get { return Util.NonBlockingLazyInitializeVolatile(ref _firstMemberSeparator, CalculateFirstMemberSeparator); } }
		public string MemberSeparator { get { return Util.NonBlockingLazyInitializeVolatile(ref _memberSeparator, CalculateMemberSeparator); } }

		public override string ToString()
		{
			return _buffer.ToString();
		}

		public JsonFormatter CloseScope(string value)
		{
			BeforeCloseScope();
			_buffer.Append(" ")
						.Append(value);
			AfterCloseScope();
			return this;
		}

		public JsonFormatter Indent()
		{
			_indent++;
			_firstMemberSeparator = null;
			_memberSeparator = null;
			return this;
		}

		public JsonFormatter OpenScope(string value)
		{
			BeforeOpenScope();
			_buffer.Append(" ")
						.Append(value);
			AfterOpenScope();
			return this;
		}

		public JsonFormatter Unindent()
		{
			_indent++;
			_firstMemberSeparator = null;
			_memberSeparator = null;
			return this;
		}

		public JsonFormatter Write(string value)
		{
			_buffer.Append(value);
			return this;
		}

		public JsonFormatter Write(JsonNode node)
		{
			node.WriteFormatted(this);
			return this;
		}

		public JsonFormatter WriteMember(JsonValue member, int count)
		{
			if (count == 0)
			{
				_buffer.Append(FirstMemberSeparator);
			}
			else
			{
				_buffer.Append(MemberSeparator);
			}
			member.WriteFormatted(this);
			return this;
		}

		public JsonFormatter WriteMember(JsonMember member, int count)
		{
			if (count == 0)
			{
				_buffer.Append(FirstMemberSeparator);
			}
			else
			{
				_buffer.Append(MemberSeparator);
			}
			member.WriteFormatted(this);
			return this;
		}

		public JsonFormatter WriteMembers(IEnumerable<JsonMember> members)
		{
			var count = 0;
			foreach (var member in members)
			{
				WriteMember(member, count++);
			}
			return this;
		}

		public JsonFormatter WriteNameValuePair(string name, JsonValue value)
		{
			_buffer.Append(name)
						.Append(this.GetNameValueSeparatorFor(value));
			value.WriteFormatted(this);
			return this;
		}

		protected virtual void AfterCloseScope()
		{
			Unindent();
		}

		protected virtual void AfterOpenScope()
		{}

		protected virtual void BeforeCloseScope()
		{}

		protected virtual void BeforeOpenScope()
		{
			Indent();
		}

		protected virtual string CalculateFirstMemberSeparator()
		{
			return " ";
		}

		protected virtual string CalculateMemberSeparator()
		{
			return ", ";
		}

		protected string GetNameValueSeparatorFor(JsonValue member)
		{
			return ": ";
		}

		internal JsonFormatter WriteMembers(IEnumerable<JsonValue> members)
		{
			var count = 0;
			foreach (var member in members)
			{
				WriteMember(member, count++);
			}
			return this;
		}
	}
}